package org.trinity.netdisk.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.trinity.netdisk.entity.User;
import org.trinity.netdisk.exception.file.OperationFailedException;
import org.trinity.netdisk.exception.user.ExistEmailException;
import org.trinity.netdisk.exception.user.InvalidParamterException;
import org.trinity.netdisk.exception.user.InvalidVerificationCodeException;
import org.trinity.netdisk.exception.user.NotExistEmailException;
import org.trinity.netdisk.mapper.UserMapper;
import org.trinity.netdisk.mapper.UserRoleMapper;
import org.trinity.netdisk.service.IUserService;
import org.trinity.netdisk.util.JWTUtil;
import org.trinity.netdisk.util.MailUtil;

import javax.annotation.Resource;

@Service
@Transactional
public class UserServiceImpl implements IUserService {

    @Resource
    UserMapper userMapper;

    @Resource
    UserRoleMapper userRoleMapper;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private final String FORGET_PASSWD_VERIFICATION_CODE = "FORGET_PASSWD_VERIFICATION_CODE";

    @Override
    public String login(User user) {
        user = userMapper.select(user.getUserName(), user.getPassword());
        return user == null ? null : JWTUtil.sign(user);
    }

    @Override
    public void register(User user, String verCode) throws InvalidParamterException {
        String redisVerCode = stringRedisTemplate.opsForValue().get(user.getEmail());
        if (redisVerCode == null || !redisVerCode.equals(verCode)) {
            throw new InvalidVerificationCodeException();
        }
        if (user.getUserName().trim().length() < 6 || user.getPassword().length() < 6 || user.getUserName().indexOf('@') != -1) {
            throw new InvalidParamterException();
        }
        userMapper.insert(user);
        userRoleMapper.insert(user.getId(),1L);
    }

    @Override
    public boolean isExistUsername(String username) {
        return userMapper.selectByUsername(username) != null;
    }

    @Override
    public boolean isExistEmail(String email) {
        return userMapper.selectByEmail(email) != null;
    }

    @Override
    public void sendVerificationCode(String email) {
        if (userMapper.selectByEmail(email) == null) {
            StringBuilder verCode = new StringBuilder();
            for (int i = 0; i < 5; i++) {
                verCode.append((int) (Math.random() * 10));
            }
            mailUtil.sendTo(email, verCode.toString());
            stringRedisTemplate.opsForValue().set(email, verCode.toString());
        } else {
            throw new ExistEmailException();
        }
    }

    @Override
    public void sendResetPasswdVerificationCode(String email){
        if (userMapper.selectByEmail(email) != null) {
            StringBuilder verCode = new StringBuilder();
            for (int i = 0; i < 5; i++) {
                verCode.append((int) (Math.random() * 10));
            }
            mailUtil.sendTo(email, verCode.toString());
            stringRedisTemplate.opsForHash().put(FORGET_PASSWD_VERIFICATION_CODE,email,verCode.toString());
        } else {
            throw new NotExistEmailException();
        }
    }

    @Override
    public void resetPasswd(String email, String password, String verCode) {
        boolean isUpdated;
        String redisVerCode = (String) stringRedisTemplate.opsForHash().get(FORGET_PASSWD_VERIFICATION_CODE,email);
        if(verCode.equals(redisVerCode)){
            isUpdated = userMapper.updatePasswdByEmail(email,password) > 0;
        }else {
            throw new InvalidVerificationCodeException();
        }
        if(!isUpdated){
            throw new OperationFailedException();
        }
        stringRedisTemplate.opsForHash().delete(FORGET_PASSWD_VERIFICATION_CODE,email);
    }
}
